﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Collections;
using System.Threading;
using SDT.Libraries.Utilities;
using SDT.DataService.Repositories;
using SDT.DataService.Services;
using SDT.DataService;
using SDT.ServiceSystem;
using System.Linq;

namespace SDT.CrawlSystem.MediaSrv
{

    public sealed class MDContainer
    {
        // Workers list
        private IDictionary<string, IWorkerThread> Workers = new Dictionary<string, IWorkerThread>();
        private Thread m_thread = null;
        #region Logging
       
        #endregion
      
        #region  List Link Download
        private int TotalThread = Global.Instance.MaxThread;
        private int BatchCount = Global.Instance.BatchSize;

        //private int MaxID = 0;

        private LinkDownloadService svLink = new LinkDownloadService();
        //public List<Spider_LinkDownload> ListDownload = new List<Spider_LinkDownload>();
        #endregion

        #region Singleton pattern
        private static MDContainer instance = new MDContainer();
        public static MDContainer Instance
        {
            get
            {
                return instance;
            }
        }

        private MDContainer()
        {
        }
        #endregion

        #region Method
        public void Remove(IWorkerThread worker)
        {
            lock (Workers)
                Workers.Remove((worker as MDCrawler).CurThread.ToString());
        }

        public void StartAll()
        {
            lock (instance)
            {
                try
                {  

                    #region Load DB
                    //IList<Spider_LinkDownload> list = svLink.GetList(BatchCount, (byte)Global.Status.SUCESS, 150, ref MaxID); // Lấy tất cả danh sách linkdownload trong một lần quest
                    IList<Spider_LinkDownload> list = svLink.GetBatchSizeList(); // Lấy danh sách linkdownload từ store procedure
                    if (list.Count == 0) return;
                    //lock (ListDownload)
                    //{
                    //    foreach (Spider_LinkDownload itm in list)
                    //    {
                    //        ListDownload.Add(itm);
                    //    }
                    //}
                    
                    new LogException().Write(string.Format("To state = {0},Module {1} - Load DB Count Record {2}- MaxID {3}", m_thread.ThreadState, "Start All", list.Count, ""));

                    #endregion

                    #region Create sub new thread
                    //lock (instance)
                    //{

                    if (list.Count < TotalThread)
                        TotalThread = 1;

                    for (int i = 1; i <= TotalThread; i++)
                    {
                        if (!instance.Workers.ContainsKey(i.ToString()))
                        {
                            instance.Workers.Add(i.ToString(), new MDCrawler(i, LoadDataMDCrawler(i, TotalThread, list), instance));
                        }
                    }
                    //}
                    #endregion

                    //clear DB
                    lock (list)
                    {
                        list.Clear();
                    }
                    //start thread
                    lock (Workers)
                        foreach (var w in Workers.Values)
                        {
                            w.StartWorking();
                        }
                }
                catch (Exception ex)
                {
                    new LogException().Write(string.Format("To state = {0},Module {1} - Message {1}", m_thread.ThreadState, "StartAll", ex.StackTrace));
                }
            }
        }
        private IDictionary<int, IList<MDWorkUnit>> LoadDataMDCrawler(int curThread, int totalThread, IList<Spider_LinkDownload> ListDownload)
        {
            lock (ListDownload)
            {
                IDictionary<int, IList<MDWorkUnit>> WorkUnitList = new Dictionary<int, IList<MDWorkUnit>>();
                int steps = (int)ListDownload.Count / TotalThread;
                int num2 = ListDownload.Count - TotalThread * steps;

                if (!WorkUnitList.ContainsKey(curThread))
                    WorkUnitList.Add(curThread, new List<MDWorkUnit>());
                else return null;

                if (steps == 0 && TotalThread == 1)
                {
                    for (int j = 0; j < ListDownload.Count; j++)
                    {
                        WorkUnitList[curThread].Add(new MDWorkUnit(ListDownload[j].DowloadID,
                            (int)ListDownload[j].CategoryID,
                            ListDownload[j].PageID,
                            ListDownload[j].LinkURL.ToString(),
                            (Convert.ToDateTime(ListDownload[j].CreatedDate)).ToString("yyyyMMdd")));
                    }
                }
                else if (steps > 0 && num2 > 0)
                {
                    if (curThread < TotalThread)
                    {
                        for (int j = (curThread - 1) * steps; j < curThread * steps; j++)
                        {
                            WorkUnitList[curThread].Add(new MDWorkUnit(ListDownload[j].DowloadID,
                                (int)ListDownload[j].CategoryID,
                                ListDownload[j].PageID,
                                ListDownload[j].LinkURL.ToString(),
                                 (Convert.ToDateTime(ListDownload[j].CreatedDate)).ToString("yyyyMMdd")));
                        }
                    }
                    else if (curThread == TotalThread)
                    {
                        for (int k = (curThread - 1) * steps; k < ListDownload.Count; k++)
                        {
                            WorkUnitList[curThread].Add(new MDWorkUnit(ListDownload[k].DowloadID,
                                (int)ListDownload[k].CategoryID,
                                ListDownload[k].PageID,
                                ListDownload[k].LinkURL.ToString(),
                                (Convert.ToDateTime(ListDownload[k].CreatedDate)).ToString("yyyyMMdd")));
                        }
                    }
                }
                else if (steps > 0 && num2 == 0)
                {
                    for (int j = (curThread - 1) * steps; j < curThread * steps; j++)
                    {
                        WorkUnitList[curThread].Add(new MDWorkUnit(ListDownload[j].DowloadID,
                            (int)ListDownload[j].CategoryID,
                            ListDownload[j].PageID,
                            ListDownload[j].LinkURL.ToString(),
                           (Convert.ToDateTime(ListDownload[j].CreatedDate)).ToString("yyyyMMdd")));
                    }

                }

                return WorkUnitList;
            }

        }

        public bool StopAll()
        {
            lock (Workers)
                foreach (var w in Workers.Values)
                    if (!w.StopWorking())
                        return false;

            return true;
        }

        public bool ClearWorker()
        {
            StopAll();
            lock (Workers)
            {
                Workers.Clear();
            }
            return true;
        }

        public void ChildProcess()
        {
            lock (m_thread)
            {
                try
                {
                    while (true)
                    {
                        #region Stop worker
                        lock (Workers)
                        {
                            if (Workers.Values.Count > 0) return;
                            else ClearWorker();
                        }
                        #endregion
                        Thread.Sleep(1000);

                        StartAll();
                        Thread.Sleep(Global.Instance.IntervalBatch);
                    }
                }
                catch (Exception ex)
                {
                   new LogException().Write(string.Format("To state = {0},Module {1} - Message {1}", m_thread.ThreadState, "ChildProcess", ex.StackTrace));
                }
                Thread.Sleep(5000);
            }

        }
              
       
        public void StartBegin()
        {       
                ThreadStart ts = new ThreadStart(this.ChildProcess);
                m_thread = new Thread(ts);
                m_thread.IsBackground = true;
                m_thread.Start();          
           
        }
        #endregion

        #region Rule get Data

      

        #endregion

    }
}